<?php

/**
 *  支付回调处理
 */

namespace app\api\service;

use app\admin\model\ProductSoldStat as ProductSoldStatModel;
use app\api\model\CoinpalRecord;
use app\api\model\Customer;
use app\api\model\Order as ModelOrder;
use app\api\model\OrderPayment as ModelOrderPayment;
use app\common\exception\ThrowException;
use think\facade\Db;
use think\facade\Log;
use app\api\service\GoAffPro;
use app\common\service\Mail as MailService;
use app\common\service\Inventory;
use app\common\service\DingTalk;
use app\common\service\CompleteNotificationService;

class CoinPal
{

    protected $initial_order_pay_status = 1;

    /**
     *  普通订单处理
     */
    public function handlePaymentCallbacks(array $notifyData)
    {
        try {
            // 1. 验证支付状态和回调数据
            $validationResult = $this->validateCallbackAndPaymentStatus($notifyData);

            // 如果是非成功支付状态，直接返回
            if ($validationResult === null) {
                return $this->buildResponse(0, 'success, 非支付成功状态,无需处理', true);
            }

            if ($validationResult === true) {
                return $this->buildResponse(0, 'success, 客户支付金额大于订单总金额, 创建新的支付记录', true);
            } else {
                [$order, $paymentRecord] = $validationResult;
            }

            $initial_order_pay_status = $order->pay_status;

            // 2. 处理支付逻辑
            $this->processPayment($order, $paymentRecord, $notifyData);

            // 3. 锁定库存
            $this->lockInventory($order, $initial_order_pay_status);

            // 4. 后续处理（邮件、GoAffPro等）
            if ($this->initial_order_pay_status != 3) { // 只有初始订单状态为未支付时，才处理后续操作
                $this->handlePostPaymentActions($order);
            }

            return $this->buildResponse(0, 'success', true);
        } catch (\Exception $e) {
            Log::error(
                'CoinPal支付回调失败: ' . $e->getMessage() .
                    ' | 文件：' . $e->getFile() .
                    ' | 行号：' . $e->getLine()
            );
            return $this->buildResponse(1, $e->getMessage(), false);
        }
    }

    /**
     * 验证支付状态和回调数据
     * 优先检查支付状态，避免不必要的数据库查询
     */
    private function validateCallbackAndPaymentStatus(array $notifyData)
    {
        // 1. 首先检查支付状态，非成功状态直接返回null
        if (!in_array($notifyData['status'], ['paid', 'partial_paid'])) {
            return null;
        }

        // 2. 验证订单是否存在
        $order = ModelOrder::where('order_no', $notifyData['orderNo'])->find();
        if (empty($order)) {
            throw new ThrowException([
                'message' => 'CoinPal支付回调订单不存在'
            ]);
        }

        // 3. 验证支付记录是否存在
        $paymentRecord = ModelOrderPayment::where('pay_code', $notifyData['requestId'])
            ->where('status', '03')
            ->where('order_no', $notifyData['orderNo'])
            ->where('payment_method', '1')
            ->find();
        if (empty($paymentRecord)) {
            if ($notifyData['status'] == 'paid') { // 如果订单状态为已支付，则创建新的支付记录
                $paymentRecord = ModelOrderPayment::where('pay_code', $notifyData['requestId'])
                    ->where('order_id', $order->id)
                    ->where('status', '01')
                    ->where('payment_method', '1')
                    ->sum('paid_amount');
                if ($notifyData['paidOrderAmount'] > $paymentRecord) {
                    ModelOrderPayment::insert([
                        'voucher_code' => $notifyData['reference'],
                        'order_id' => $order->id,
                        'payment_method' => '1',
                        'payment_method_name' => 'Crypto Pay',
                        'pay_type' => '00',
                        'pay_amount' => 0,
                        'create_time' => date('Y-m-d H:i:s'),
                        'status' => '01',
                        'order_type' => $order->order_category,
                        'order_no' => $order->order_no,
                        'user_id' => $order->user_id,
                        'pay_code' => $notifyData['requestId'],
                        'paid_amount' => $notifyData['paidOrderAmount'] - $paymentRecord,
                        'pay_time' => date('Y-m-d H:i:s'),
                        'notes' => 'CoinPal支付回调, 客户支付金额大于订单总金额, 创建新的支付记录',
                    ]);
                    return true;
                }
            }
            throw new ThrowException([
                'message' => 'Invalid requestId,未找到相关支付记录'
            ]);
        }

        return [$order, $paymentRecord];
    }



    /**
     * 处理支付逻辑
     */
    private function processPayment($order, $paymentRecord, array $notifyData)
    {
        Db::startTrans();
        try {
            $notifyData['user_id'] = $order->user_id;
            $notifyData['order_id'] = $order->id;

            if ($notifyData['status'] === 'partial_paid') {
                // 更新当前支付记录
                $this->updateOrderPaymentStatus($paymentRecord, '01', $notifyData['paidOrderAmount'], $notifyData);
                // 计算已支付金额和剩余金额
                $paidAmount = $this->calculatePaidAmount($order->id);
                $remainingAmount = $order->total_amount - $paidAmount;
                if ($remainingAmount > 0) {
                    // 创建新的支付记录用于剩余金额
                    ModelOrderPayment::insert([
                        'order_id' => $order->id,
                        'payment_method' => '1',
                        'payment_method_name' => 'Crypto Pay',
                        'pay_type' => '00',
                        'pay_amount' => $remainingAmount,
                        'create_time' => date('Y-m-d H:i:s'),
                        'status' => '03',
                        'order_type' => $order->order_category,
                        'order_no' => $order->order_no,
                        'user_id' => $order->user_id,
                        'pay_code' => $paymentRecord->pay_code,
                        'pay_currency' => $paymentRecord->pay_currency,
                        'payment_url' => $paymentRecord->payment_url,
                        'paid_amount' => null,
                    ]);
                    // 更新订单状态
                    $this->updateOrderStatus($order, $paidAmount, 4); // 部分支付状态
                } else {
                    $this->handleCompletePayment($order, $paidAmount);
                }
            } else {
                // 更新支付记录
                $this->updateOrderPaymentStatus($paymentRecord, '01', $notifyData['paidOrderAmount'], $notifyData);

                // 计算总支付金额
                $paidAmount = $this->calculatePaidAmount($order->id);

                // 只有在订单未完全支付时才更新状态
                if ($order->pay_status != 3) {
                    if ($order->total_amount <= $paidAmount) {
                        $this->handleCompletePayment($order, $paidAmount);
                    } else {
                        $this->updateOrderStatus($order, $paidAmount, 4); // 继续支付
                    }
                }
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            throw new ThrowException([
                'message' => 'CoinPal支付数据库事务失败: ' . $e->getMessage()
            ]);
        }
    }



    /**
     * 处理完全支付
     */
    private function handleCompletePayment($order, $paidAmount)
    {
        if ($order->pay_status == 3) { // 订单已支付，不重复处理
            $this->initial_order_pay_status = 3;
            return;
        }
        if ($order->order_category == 'wholesal') {
            $status = 100;
        } else {
            $status = 30;
        }
        // 更新订单状态
        $this->updateOrderStatus($order, $paidAmount, 3, $status);

        // 客户阶段自动维护
        $this->autoUserStage($order);
    }

    /**
     * 更新支付记录
     * $paidAmount 累计实付金额
     */
    private function updateOrderPaymentStatus($paymentRecord, string $status, $paidAmount, $notifyData)
    {

        $currentPaidAmount = Db::name('order_payment')
            ->where('payment_method', $paymentRecord->payment_method)
            ->where('pay_code', $paymentRecord->pay_code)
            ->where('order_id', $paymentRecord->order_id)
            ->where('status', '01')
            ->sum('paid_amount');
        $paymentRecord->voucher_code = $notifyData['reference'];
        $paymentRecord->status = $status;
        $paymentRecord->paid_amount = $paidAmount - $currentPaidAmount;
        $paymentRecord->update_time = date('Y-m-d H:i:s');
        $paymentRecord->pay_time = date('Y-m-d H:i:s');
        $paymentRecord->save();
    }

    /**
     * 计算已支付金额
     */
    private function calculatePaidAmount(int $orderId): float
    {
        return (float) Db::name('order_payment')
            ->where('order_id', $orderId)
            ->where('status', '01')
            ->sum('paid_amount');
    }



    /**
     * 更新订单支付状态
     */
    private function updateOrderStatus($order, $paidAmount, int $payStatus, ?int $orderStatus = null)
    {
        $order->pay_amount = $paidAmount;
        $order->pay_status = $payStatus;

        if ($orderStatus !== null) {
            $order->status = $orderStatus;
        }

        if (null == $order->pay_time) { // 记录订单首次支付时间
            $order->pay_time = date('Y-m-d H:i:s');
        }

        if (!$order->save()) {
            throw new ThrowException([
                'message' => 'CoinPal支付修改订单状态失败'
            ]);
        }
    }

    /**
     * 锁定库存
     */
    private function lockInventory($order, $initial_order_pay_status)
    {

        if (1 === $initial_order_pay_status && in_array($order->pay_status, [3, 4]) && 2 !== $order->order_type) { // 只有初始订单支付状态为未支付时，才锁定库存
            $inventory = new Inventory();
            $lockResult = $inventory->lockInventory($order->toArray());
            if (!$lockResult) {
                Db::startTrans();
                try {
                    $order->review_node = 1;
                    $order->exceptionstatus = $order->exceptionstatus ? $order->exceptionstatus . ',1' : 1;
                    $order->save();
                    Db::name('order_item')->where('order_id', $order->id)->update(['exceptionstatus' => 1]);
                    Db::commit();
                } catch (\Exception $e) {
                    Db::rollback();
                    Log::error('CoinPal支付锁定库存成功,修改订单异常状态失败, order_id: ' . $order->id . ' 错误信息: ' . $e->getMessage());
                }

                $operator = DB::name('operator')
                    ->where('is_del', 0)
                    ->where(function ($query) {
                        $query->whereRaw("FIND_IN_SET('40', job)")
                            ->whereOr(function ($subQuery) {
                                $subQuery->whereRaw("FIND_IN_SET('41', job)");
                            })
                            ->whereOr(function ($subQuery) {
                                $subQuery->whereRaw("FIND_IN_SET('50', job)");
                            })
                            ->whereOr(function ($subQuery) {
                                $subQuery->whereRaw("FIND_IN_SET('51', job)");
                            });
                    })
                    ->column('id');
                if (!empty($operator)) {
                    $domain = config('domain')[env('APP_ENV')]['erphome'];
                    if ($order->order_category == 'wholesal') {
                        $url  = $domain . '/#/order/wholesal-order-management';
                    } else {
                        $url = $domain . '/#/order/order-management';
                    }
                    $dingTalk = new DingTalk();
                    $dingTalk->SendActionCardJobNotificationMessage(
                        'CoinPal支付锁定库存失败',
                        'CoinPal支付锁定库存失败, 订单编号: ' . $order->order_no,
                        $url,
                        $operator,
                    );
                }
                Log::error('CoinPal支付锁定库存失败, order_id: ' . $order->id);
            }
        }
    }

    /**
     * 处理支付后的操作
     */
    private function handlePostPaymentActions($order)
    {  // 发送邮件
        $emailService = new MailService();


        if ($order->pay_status == 3) {
            // 修改GoAffPro订单状态
            $goAffPro = new GoAffPro();
            $goAffPro->updateAffiliateOrder(true, $order->id);
            $emailService->send('order_payment', $order->toArray());
            $event = 'order_payment';
        } else {
            $emailService->send('order_partial_payment', $order->toArray());
            $event = 'order_partial_payment';
        }

        // 通知
        try {
            $customer = Customer::where('id', $order->user_id)->find();
            $notificationService = new CompleteNotificationService();
            $orderPartner = $order->partner ? array_filter(explode(',', $order->partner)) : [];
            $recipients = array_filter(array_unique([$customer->owner, $order->owner,$order->signatory, ...$orderPartner]));
            $notificationService->send($event, $order->toArray(), $recipients); // 支付通知

            if (30 == $order->status) {
                $notificationService->send('order_delivery_pending', $order->toArray(), [], '', '50,51'); // 待发货通知
            }

        } catch (\Exception $e) {
            Log::error('订单支付通知发送失败: ' . $e->getMessage() . ' 订单编号: ' . $order->order_no . ' 支付方式 Coinpal | 文件：' . $e->getFile() . ' | 行号：' . $e->getLine());
        }
    }

    /**
     * 构建响应数据
     */
    private function buildResponse(int $code, string $message, $data = null): array
    {
        return [
            'code' => $code,
            'message' => $message,
            'data' => $data,
        ];
    }

    /**
     * 客户阶段自动维护
     */
    private function autoUserStage($order)
    {
        $customer = Customer::where(['id' => $order->user_id])->field('id,stage')->find();
        if ($customer->stage < 3) {
            $customer->stage = 3;
            $customer->save();
        }
    }

    /**
     *  写入 Order Payment 日志
     */
    public function writeCoinPalRecord($data)
    {
        $notifyData['user_id'] = $data['user_id'];
        $notifyData['order_id'] = $data['order_id'];
        $notifyData['request_id'] = $data['requestId'];
        $notifyData['order_no'] = $data['orderNo'];
        $notifyData['reference'] = $data['reference'];
        $notifyData['order_currency'] = $data['orderCurrency'];
        $notifyData['order_amount'] = $data['orderAmount'];
        $notifyData['paid_order_amount'] = $data['paidOrderAmount'];
        $notifyData['selected_wallet'] = $data['selectedWallet'];
        $notifyData['due_currency'] = $data['dueCurrency'];
        $notifyData['due_amount'] = $data['dueAmount'];
        // $notifyData['network'] = $data['network'];
        $notifyData['paid_currency'] = $data['paidCurrency'];
        $notifyData['paid_amount'] = $data['paidAmount'];
        //   $notifyData['payment_method'] = $data['paymentMethod'];
        $notifyData['paid_usdt'] = $data['paidUsdt'];
        $timestamp = isset($data['confirmedTime']) ? intval($data['confirmedTime']) : time();
        $notifyData['confirmed_time'] = date("Y-m-d H:i:s", $timestamp);
        $notifyData['pay_status'] = $data['status'];
        $notifyData['remark'] = $data['remark'];
        $notifyData['unresolved_label'] = $data['unresolvedLabel'];
        $notifyData['create_time'] = date("Y-m-d H:i:s", time());
        // 状态
        //$notifyData['status'] = $data['status'];

        return CoinpalRecord::create($notifyData);
    }

    /**
     * 库存盘点
     * @param $productid
     * @param $warehouse_id
     * @param $available_qty_change
     * @param $total_qty_change
     * @param $pending_qty_change
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2025-03-07 16 55 36
     * author: jiang
     */
    public function productSoldStat($productid, $warehouse_id, $available_qty_change, $total_qty_change, $pending_qty_change)
    {
        $exist = ProductSoldStatModel::where(['productid' => $productid, 'warehouse_id' => $warehouse_id])->find();
        $oProductSoldStatModel = $exist ?? new ProductSoldStatModel();

        // 如果是新记录，初始化数量字段
        if (!$exist) {
            $oProductSoldStatModel->productid = $productid;
            $oProductSoldStatModel->warehouse_id = $warehouse_id;
            $oProductSoldStatModel->available_qty = $available_qty_change;
            $oProductSoldStatModel->total_qty = $total_qty_change;
            $oProductSoldStatModel->pending_qty = $pending_qty_change;
            $oProductSoldStatModel->create_time = date('Y-m-d H:i:s');
            $oProductSoldStatModel->save();
        } else {
            // 根据传入的变动值更新数量
            if ($available_qty_change >= 0) {
                $oProductSoldStatModel->inc('available_qty', abs($available_qty_change));
            } else {
                $oProductSoldStatModel->dec('available_qty', abs($available_qty_change));
            }
            if ($total_qty_change >= 0) {
                $oProductSoldStatModel->inc('total_qty', abs($total_qty_change));
            } else {
                $oProductSoldStatModel->dec('total_qty', abs($total_qty_change));
            }
            if ($pending_qty_change >= 0) {
                $oProductSoldStatModel->inc('pending_qty', abs($pending_qty_change));
            } else {
                $oProductSoldStatModel->dec('pending_qty', abs($pending_qty_change));
            }
            $oProductSoldStatModel->update_time = date('Y-m-d H:i:s');
        }

        // 保存更新后的记录
        $oProductSoldStatModel->save();
    }
}
